#include <glib.h>

#define TEST_ARRAY_LEN 4

static void _test_hash_str_foreach_func(gpointer key, gpointer value, gpointer user_data)
{
    g_print("%s key: %s, value: %s \n", (gchar *)user_data, (gchar *)key, (gchar *)value);
    return;
}

static void _test_hash_str_key_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void _test_hash_str_value_destroy_func(gpointer data)
{
    if(NULL != data) {
        g_free(data);
    }
}

static void test_hash_contains(void)
{
    gint i = 0;
    gboolean ret = FALSE;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    ret = g_hash_table_contains(htable, key[TEST_ARRAY_LEN/2]);
    g_print("%s %s in hash table \n", key[TEST_ARRAY_LEN/2], ret?"is":"is Not");

    g_hash_table_destroy(htable);

    return;
}

static void test_hash_lookup(void)
{
    gint i = 0;
    char *value = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        if(1 == i) {
            g_free(val[i]);
            g_hash_table_insert(htable, key[i], NULL);
        } else {
            g_hash_table_insert(htable, key[i], val[i]);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    value = g_hash_table_lookup(htable, key[1]);
    if(NULL == value) {
        g_print("key[1] value is NULL \n");
    } else {
        g_print("key[1] value is %s \n", value);
    }

    value = g_hash_table_lookup(htable, key[2]);
    if(NULL == value) {
        g_print("key[1] value is NULL \n");
    } else {
        g_print("key[2] value is %s \n", value);
    }

    value = g_hash_table_lookup(htable, "key9");
    if(NULL == value) {
        g_print("key9 value is NULL \n");
    } else {
        g_print("key9 value is %s \n", value);
    }

    g_hash_table_destroy(htable);

    return;
}

static void test_hash_lookup_extended(void)
{
    gint i = 0;
    gboolean ret = FALSE;
    char *ori_key = NULL;
    char *ori_value = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        if(1 == i) {
            g_free(val[i]);
            g_hash_table_insert(htable, key[i], NULL);
        } else {
            g_hash_table_insert(htable, key[i], val[i]);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    ret = g_hash_table_lookup_extended(htable, "key1", (gpointer *)&ori_key, (gpointer *)&ori_value);
    if(TRUE == ret) {
        g_print("key1 found, ori_key: %s, value: %s \n", ori_key, ori_value);
    } else {
        g_print("key1 not found \n");
    }

    ret = g_hash_table_lookup_extended(htable, "key9", (gpointer *)&ori_key, (gpointer *)&ori_value);
    if(TRUE == ret) {
        g_print("key9 found, ori_key: %s, value: %s \n", ori_key, ori_value);
    } else {
        g_print("key9 not found \n");
    }

    g_hash_table_destroy(htable);

    return;
}

static gboolean _test_hash_find_ghrfunc
    (gpointer key, gpointer value, gpointer user_data)
{
    if(0 == g_strcmp0((const char *)user_data, (const char *)key)) {
        return TRUE;
    }

    return FALSE;
}

static void test_hash_find(void)
{
    gint i = 0;
    char *value = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        g_hash_table_insert(htable, key[i], val[i]);
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    value = g_hash_table_find(htable, _test_hash_find_ghrfunc, "key2");
    if(NULL != value) {
        g_print("key2 found in hash table, value: %s \n", value);
    } else {
        g_print("key2 not found in hash table \n");
    }

    value = g_hash_table_find(htable, _test_hash_find_ghrfunc, "key9");
    if(NULL != value) {
        g_print("key9 found in hash table, value: %s \n", value);
    } else {
        g_print("key9 not found in hash table \n");
    }

    g_hash_table_destroy(htable);

    return;
}

static void _test_hash_list_foreach_func(gpointer data, gpointer user_data)
{
    g_print("list data: %s \n", (gchar *)data);
}

static void test_hash_get_keys(void)
{
    gint i = 0;
    GList *list = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        if(1 == i) {
            g_free(val[i]);
            g_hash_table_insert(htable, key[i], NULL);
        } else {
            g_hash_table_insert(htable, key[i], val[i]);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    list = g_hash_table_get_keys(htable);
    g_list_foreach(list, _test_hash_list_foreach_func, NULL);
    g_list_free(list);

    g_hash_table_destroy(htable);

    return;
}

static void test_hash_get_values(void)
{
    gint i = 0;
    GList *list = NULL;
    char *key[TEST_ARRAY_LEN] = {NULL};
    char *val[TEST_ARRAY_LEN] = {NULL};
    GHashTable *htable = NULL;

    g_print("\n");

    htable = g_hash_table_new_full(g_str_hash, g_str_equal, \
        _test_hash_str_key_destroy_func, _test_hash_str_value_destroy_func);

    for(i=0; i<TEST_ARRAY_LEN; i++) {
        key[i] = g_strdup_printf("key%d", i);
        val[i] = g_strdup_printf("value%d", i);
        if(1 == i) {
            g_free(val[i]);
            g_hash_table_insert(htable, key[i], NULL);
        } else {
            g_hash_table_insert(htable, key[i], val[i]);
        }
    }

    g_hash_table_foreach(htable, _test_hash_str_foreach_func, "ori");
    g_print("htable length: %d \n", g_hash_table_size(htable));

    list = g_hash_table_get_values(htable);
    g_list_foreach(list, _test_hash_list_foreach_func, NULL);
    g_list_free(list);

    g_hash_table_destroy(htable);

    return;
}

gint main(gint argc, gchar **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func ("/hash/search/contains", test_hash_contains);
    g_test_add_func ("/hash/search/lookup", test_hash_lookup);
    g_test_add_func ("/hash/search/lookup-extended", test_hash_lookup_extended);
    g_test_add_func ("/hash/search/find", test_hash_find);
    g_test_add_func ("/hash/search/get-keys", test_hash_get_keys);
    g_test_add_func ("/hash/search/get-values", test_hash_get_values);

    return g_test_run();
}